package org.yaac.server.util;

import java.util.Arrays;

import org.yaac.shared.YaacAutoBeanFactory;
import org.yaac.shared.egql.Result;
import org.yaac.shared.egql.ResultCell;
import org.yaac.shared.egql.ResultCell.ResultCellFactory;
import org.yaac.shared.file.BlobUploadResult;
import org.yaac.shared.file.BlobUploadResult.Status;
import org.yaac.shared.file.CacheUploadResult;
import org.yaac.shared.file.FileDownloadPath;
import org.yaac.shared.file.FileDownloadPath.Type;
import org.yaac.shared.property.PropertyType;

import com.google.web.bindery.autobean.shared.AutoBean;
import com.google.web.bindery.autobean.shared.AutoBeanCodex;
import com.google.web.bindery.autobean.vm.AutoBeanFactorySource;

/**
 * AutoBeanUtil used in server side to serialize
 * 
 * @author Max Zhu (thebbsky@gmail.com)
 *
 */
public class AutoBeanUtil {

	private static final YaacAutoBeanFactory abf = AutoBeanFactorySource.create(YaacAutoBeanFactory.class);
	
	/**
	 * @param <T>
	 * @param clazz
	 * @param o
	 * @return
	 */
	public static <T> String encode(Class<T> clazz, T o) {
		AutoBean<T> source = abf.create(clazz, o);
		return AutoBeanCodex.encode(source).getPayload();
	}
	
	/**
	 * @param <T>
	 * @param clazz
	 * @param encodedStr
	 * @return
	 */
	public static <T> T decode(Class<T> clazz, String encodedStr) {
		return AutoBeanCodex.decode(abf, clazz, encodedStr).as();
	}
	
	/**
	 * @param statementKey
	 * @return
	 */
	public static Result newResult(String statementKey) {
		Result obj = abf.statementResult().as();
		obj.setStatementKey(statementKey);
		return obj;
	}
	
	private static ResultCellFactory resultCellFactory;

	/**
	 * @return singleton of ResultCellFactory 
	 */
	public static synchronized ResultCellFactory getResultCellFactory() {
		if (resultCellFactory == null) {
			resultCellFactory = new ResultCellFactory() {
				@Override
				public ResultCell create() {
					return AutoBeanUtil.newResultCell();
				}
			};
		}
		
		return resultCellFactory;
	}
	
	/**
	 * @return
	 */
	public static ResultCell newResultCell() {
		return abf.resultCell().as();
	}
	
	/**
	 * @param null1
	 * @param object
	 * @return
	 */
	public static ResultCell newResultCell(PropertyType type, String ...payloads) {
		ResultCell result = newResultCell();
		result.setType(type);
		result.setPayload(Arrays.asList(payloads));
		return result;
	}
	
	/**
	 * @param type
	 * @param keyStr
	 * @param fieldName
	 * @param index
	 * @param fileName
	 * @param size
	 * @return
	 */
	public static FileDownloadPath newFileDownloadPath(
			FileDownloadPath.Type type, 
			String keyStr, 
			String fieldName, Integer index, 
			String fileName, Integer size) {
		FileDownloadPath path = abf.fileDownloadPath().as();
		path.setType(type);
		path.setKeyStr(keyStr);
		path.setFieldName(fieldName);
		path.setIndex(index);
		path.setFileName(fileName);
		path.setSize(size);
		return path;
	}
	
	/**
	 * @param status 
	 * @param fileName 
	 * @param size 
	 * @return
	 */
	public static BlobUploadResult newBlobUploadResult(Status status, String fileName, Integer size) {
		BlobUploadResult result = abf.blobUploadResult().as();
		result.setStatus(status);
		result.setFileName(fileName);
		result.setSize(size);
		return result;
	}
	
	/**
	 * @param status
	 * @param cacheKey
	 * @param fileName
	 * @param size
	 * @return
	 */
	public static CacheUploadResult newCacheUploadResult(CacheUploadResult.Status status, 
			String cacheKey, String fileName, Integer size) {
		CacheUploadResult result = abf.cacheUploadResult().as();
		result.setStatus(status);
		result.setPath(newFileDownloadPath(Type.MEMCACHE, cacheKey, null, null, fileName, size));
		return result;
	}
	
	/**
	 * @param cacheKey
	 * @return
	 */
	public static FileDownloadPath cacheDownloadPath(String cacheKey) {
		FileDownloadPath path = abf.fileDownloadPath().as();
		path.setType(Type.MEMCACHE);
		path.setKeyStr(cacheKey);
		path.setFieldName(null);
		path.setIndex(null);
		return path;
	}
	
	/**
	 * @param cacheString
	 * @return
	 */
	public static String cacheDownladPathString(String cacheString) {
		FileDownloadPath path = cacheDownloadPath(cacheString);
		return encode(FileDownloadPath.class, path);
	}
}
